package com.example.seckilldemo.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.example.seckilldemo.config.AccessLimit;
import com.example.seckilldemo.exception.GlobalException;
import com.example.seckilldemo.pojo.Order;
import com.example.seckilldemo.pojo.SeckillMessage;
import com.example.seckilldemo.pojo.SeckillOrder;
import com.example.seckilldemo.pojo.User;
import com.example.seckilldemo.rabbitmq.MQSender;
import com.example.seckilldemo.service.IGoodsService;
import com.example.seckilldemo.service.IOrderService;
import com.example.seckilldemo.service.ISeckillOrderService;
import com.example.seckilldemo.utils.JsonUtil;
import com.example.seckilldemo.vo.GoodsVo;
import com.example.seckilldemo.vo.RespBean;
import com.example.seckilldemo.vo.RespBeanEnum;
import com.wf.captcha.ArithmeticCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author Wangbaba
 * @Date 2024/3/19 17:33
 * @Version 1.0
 */
@Slf4j
@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    private Map<Long,Boolean> EmptyStockMap=new HashMap<>();

    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISeckillOrderService seckillOrderService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisScript<Long> script;
    @Autowired
    private MQSender mqSender;

    //秒杀
    //跳订单详情页面
    @PostMapping("/{path}/doSeckill")
    @ResponseBody
    public RespBean toSeckill(User user, Long goodsId, @PathVariable String path) {
        ValueOperations valueOperations=redisTemplate.opsForValue();
        //验证path
        boolean check=orderService.checkPath(goodsId,user,path);
        if (!check){
            throw new GlobalException(RespBeanEnum.EXIST_ERROR);
        }
        //使用redis判断 是否重复抢购
        SeckillOrder seckillOrder= (SeckillOrder) valueOperations.get("order:"+user.getId()+";"+goodsId);
        if (Objects.nonNull(seckillOrder)) {
            throw new GlobalException(RespBeanEnum.SECKILL_REPEAT_ERROR);
        }
        //内存标记 减少redis访问
        if (EmptyStockMap.get(goodsId)){
            throw new GlobalException(RespBeanEnum.SECKILL_EMPTY_ERROR);
        }
        //预减库存操作
        Long stock=valueOperations.decrement("seckillGoods:"+goodsId);
        //lua脚本 预减库存操作
//        Long stock= (Long) redisTemplate.execute(script, Collections.singletonList("seckillGoods:"+goodsId),Collections.EMPTY_LIST);
        if (stock<0){
            EmptyStockMap.put(goodsId,true);
            valueOperations.increment("seckillGoods:"+goodsId);
            throw new GlobalException(RespBeanEnum.SECKILL_EMPTY_ERROR);
        }
        //消息队列发送消息
        SeckillMessage seckillMessage=new SeckillMessage(user,goodsId);
        mqSender.sendSeckillMsg(JsonUtil.object2JsonStr(seckillMessage));
        return RespBean.success(0);
    }

    /**
     * 获取秒杀结果 orderId成功  -1失败   0排队中
     * @throws Exception
     */
    @GetMapping("/result")
    @ResponseBody
    public RespBean getResult(User user,Long goodsId){
        Long orderId = seckillOrderService.getResult(user,goodsId);
        return RespBean.success(orderId);
    }

    /**
     * 获取秒杀地址
     * @return
     */
    @AccessLimit(second=5,maxCount=5,needLogin=true)
    @GetMapping("/path")
    @ResponseBody
    public RespBean getPath(Long goodsId,String captcha,User user,HttpServletRequest request){
        boolean check=orderService.checkCaptcha(goodsId,captcha,user);
        if (!check){
            throw new GlobalException(RespBeanEnum.CAPTCHA_ERROR);
        }
        String str=orderService.createPath(goodsId,user);
        return RespBean.success(str);
    }

    /**
     * 获取验证码
     */
    @GetMapping("/captcha")
    public void verifyCode(User user, Long goodsId, HttpServletRequest request, HttpServletResponse response){
        //设置请求头为输出图片的类型
        response.setContentType("image/jpg");
        response.setHeader("Pargam","No-cache");
        response.setHeader("Cache-control","no-cache");
        response.setDateHeader("Expires",0);
        //生成验证码，将结果输入到redis
        ArithmeticCaptcha captcha=new ArithmeticCaptcha(130,32,3);
        redisTemplate.opsForValue().set("captcha:"+user.getId()+":"+goodsId,captcha.text(),300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        } catch (IOException e) {
            log.error("验证码生成失败",e.getMessage());
        }
    }

    /**
     * 系统初始化时执行的方法 把商品库存加载到redis
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> goodsVos=goodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(goodsVos)){
            return;
        }
        goodsVos.forEach(goodsVo -> {
            redisTemplate.opsForValue().set("seckillGoods:"+goodsVo.getId(),goodsVo.getStockCount());
            EmptyStockMap.put(goodsVo.getId(),false);
        });
    }
}
